import React, { Component } from 'react';
import { connect } from 'react-redux';
import SockJS from 'sockjs-client';
import Stomp from 'stompjs';
import {
    Alert
} from 'react-bootstrap';

import {
    TaskStatus,
} from '../../config';
import {
    function_deploy_pro_task,
    function_deploy_test_task,
    function_deploy_prev_task,
    function_get_logger
} from '../../actions/deploy';

import './less/deploy.css'; 

class App extends Component {

    state = {
        parseLogFlg: false, //是否解析了日志
        servs: [], //微服务列表
        stompClient: null, //消息推送客户端
        showResult: false, //展示上线结果
        resultMessage: "", //结果文字信息
        svg_stage: 0, //当前执行的阶段
        svg_host: null, //当前执行的主机 
        svg_level: "info", //当前执行的阶段特征
        svg_width: 1118, //整个svg宽度
        svg_height: 40, //头部高度
        svg_interval: 34, //各个子项高度
        svg_circle: 12, //圆圈半径
        svg_length_item: 6, //横向上的元素个数
        svg_base_cirle: 15, //圆圈开始坐标
        svg_hosts: {},
        svg_grapth: {},
        svg_logs: {}
    }

    componentDidMount(){
        this.props.onRef(this);
        let svg_hosts = {};
        let svg_logs = {};
        let svg_grapth = {};
        let servs = [];
        let env;
        if(this.props.deployStatus === TaskStatus.TESTING){
            env = 1;
        }else if(this.props.deployStatus === TaskStatus.PRE_TESTING){
            env = 2;
        }else{
            env = 3;
        }
        for(let item of this.props.serversList){
            let servsId = item.servsId;
            servs.push(servsId);
            let hosts = [];
            if(env === 1){
                hosts = [this.props.testHost];
            }else if(env === 2){
                hosts = [this.props.prevHost];
            }else{
                hosts = item.servsObject.lineHost;
            }
            let grapth = {
                stage: 0,
                level: "null",
                status: 'down',
            };
            for(let host of hosts){
                grapth[host] = {
                    stage: 0,
                    level: null
                };
            }
            svg_hosts[servsId] = hosts;
            svg_logs[servsId] = [];
            svg_grapth[servsId] = grapth;
        }
        this.connectSocket();
        if(!this.state.parseLogFlg){
            this.setState({parseLogFlg: true});
            for(let servsId of servs){
                function_get_logger(this.props.deployUrl, this.props.pid, this.props.tid, servsId, env, list => {
                    for(let row of list){
                        let ret = JSON.parse(row);
                        this.dispatchLog(ret, ()=>{});
                    }
                });
            }
        }
        this.setState({
            servs: servs,
            svg_hosts: svg_hosts,
            svg_grapth: svg_grapth,
            svg_logs: svg_logs
        });
    }

    componentWillUnmount(){
        if(this.state.stompClient !== null){
            this.state.stompClient.disconnect();
        }
    }

    deploy(reloadFlg, cb){
        if(this.props.deployStatus !== TaskStatus.TESTING && this.props.deployStatus !== TaskStatus.PRE_TESTING && this.props.deployStatus !== TaskStatus.DEPLOYING){
            return;
        }
        if(reloadFlg){
            let svg_logs = {};
            let svg_grapth = {};
            for(let serverId of this.state.servs){
                let grapth = {
                    stage: 0,
                    level: null
                };
                for(let host of this.state.svg_hosts[serverId]){
                    grapth[host] = {
                        stage: 0,
                        level: null
                    };
                }
                svg_logs[serverId] = [];
                svg_grapth[serverId] = grapth;
            }
            this.setState({
                svg_logs: svg_logs,
                svg_grapth: svg_grapth
            });
        }
        if(this.props.deployStatus === TaskStatus.TESTING){
            function_deploy_test_task(this.props.deployUrl, this.props.pid, this.props.tid, reloadFlg, cb);
        }else if(this.props.deployStatus === TaskStatus.PRE_TESTING){
            function_deploy_prev_task(this.props.deployUrl, this.props.pid, this.props.tid, reloadFlg, cb);
        }else{
            function_deploy_pro_task(this.props.deployUrl, this.props.pid, this.props.tid, reloadFlg, cb);
        }
    }

    connectSocket(){
        let socket = new SockJS(this.props.deployUrl+"myWebSocket/");
        let stompClient = Stomp.over(socket);
        stompClient.debug = false;
        stompClient.connect({}, (frame) => {
            stompClient.subscribe('/topic/service', (response) => {
                let ret = JSON.parse(response.body);
                this.dispatchLog(ret, ()=>{
                    this.setState({showResult: true});
                    this.props.onFinish();
                });
            });
        });
        this.setState({stompClient: stompClient});
    }

    dispatchLog(ret, cb){
        if(ret.taskId === this.props.tid){
            let status = ret.status;
            if(status === "notice"){
                this.setState({resultMessage: ret.message});
                cb();
                return true;
            }
            let servsId = ret.servsId;
            let svg_grapth = this.state.svg_grapth;
            let grapth = svg_grapth[servsId];
            let all_logs = this.state.svg_logs;
            let logsArr = all_logs[servsId];
            let level = ret.level;
            let stage = ret.stage;
            let hostName = ret.hostName;
            if(status === "up") {
                logsArr.push(ret);
            }else if(level === "error"){
                logsArr.push(ret);
            }
            all_logs[servsId] = logsArr;
            grapth.stage = stage;
            grapth.level = level;
            grapth.status = status;
            if(hostName !== null){
                grapth[hostName] = {
                    stage: stage,
                    level: level
                };
            }
            svg_grapth[servsId] = grapth;
            this.setState({
                svg_grapth,
                svg_logs: all_logs
            });
        }
        return false;
    }

    getClassName(item, host, serverId){
        if(host == null){
            if(this.state.svg_grapth[serverId].stage < item)
                return "wait";
            else if(this.state.svg_grapth[serverId].stage > item){
                return "finish";
            }else{
                if(this.state.svg_grapth[serverId].status === "up"){
                    return "process";
                }else{
                    if(this.state.svg_grapth[serverId].level === "command"){
                        return "finish";
                    }else{
                        return "error";
                    }
                }
            }
        }else{
            if(this.state.svg_grapth[serverId][host].stage < item)
                return "wait";
            else if(this.state.svg_grapth[serverId][host].stage > item){
                return "finish";
            }else{
                if(this.state.svg_grapth[serverId].status === "up"){
                    return "process";
                }else{
                    if(this.state.svg_grapth[serverId][host].level === "command"){
                        return "finish";
                    }else{
                        return "error";
                    }
                }
            }
        }
    }

    render () {
        return (
        <div className="deployBox">
            <Alert show={this.state.showResult} variant="info" onClose={()=>this.setState({showResult: false})} dismissible>  
                {this.state.resultMessage}
            </Alert>
            {this.state.servs.map(servsId => {
            let base_svg_y = this.state.svg_interval*(this.state.svg_hosts[servsId].length - 1)/2;
            let base_svg_x = (this.state.svg_width-120)/(this.state.svg_length_item-1);
            return this.state.svg_hosts[servsId].length>0 ? 
                <div key={servsId}> 
                    <svg width={this.state.svg_width} height={this.state.svg_height + this.state.svg_interval * this.state.svg_hosts[servsId].length} className="wl-svg-tree">
                        <g>
                            <text x={base_svg_x*0} y="18" className="title">Deploy前置任务</text>
                            <text x={base_svg_x*1} y="18" className="title">Deploy</text>
                            <text x={base_svg_x*2} y="18" className="title">Deploy后置任务</text>
                            <text x={base_svg_x*3} y="18" className="title">Release前置任务</text>
                            <text x={base_svg_x*4} y="18" className="title">Release</text>
                            <text x={base_svg_x*5} y="18" className="title">Release后置任务</text>
                        </g>
                        <g transform="translate(0,40)">
                            <g className={this.getClassName(1, null, servsId)}>
                                <circle cx={this.state.svg_base_cirle} cy={base_svg_y} r={this.state.svg_circle}></circle>
                                <text x={this.state.svg_circle} y={base_svg_y + 4}>1</text>
                            </g>
                            {Object.keys(Array.apply(null, {length:this.state.svg_length_item-1})).map(item => {
                                item = parseInt(item);
                                if(item < 2){
                                    return (
                                        <g key={item} className={this.getClassName(item+2, null, servsId)}>
                                            <line x1={base_svg_x*item + (item === 0 ? this.state.svg_base_cirle : 0) + this.state.svg_circle + 2} y1={base_svg_y} x2={base_svg_x*(item+1)-this.state.svg_circle} y2={base_svg_y}></line>
                                            <circle cx={base_svg_x*(item+1)} cy={base_svg_y} r={this.state.svg_circle}></circle>
                                            <text x={base_svg_x*(item+1) - 3} y={base_svg_y + 4}>{item+2}</text>
                                        </g>
                                    )
                                }else{
                                    return this.state.svg_hosts[servsId].map((item2, index2) => {
                                        if(item === 2){
                                            return (
                                                <g key={item2} className={this.getClassName(item+2, item2, servsId)}>
                                                    <line x1={base_svg_x*item + (item === 0 ? this.state.svg_base_cirle : 0) + this.state.svg_circle + 2} y1={base_svg_y} x2={base_svg_x*(item+1)-this.state.svg_circle} y2={this.state.svg_interval*index2}></line>
                                                    <circle cx={base_svg_x*(item+1)} cy={this.state.svg_interval*index2} r={this.state.svg_circle}></circle>
                                                    <text x={base_svg_x*(item+1) - 3} y={this.state.svg_interval*index2 + 4}>{item+2}</text>
                                                </g>
                                            )
                                        }else if(item < this.state.svg_length_item - 2){
                                            return (
                                                <g key={item2} className={this.getClassName(item+2, item2, servsId)}>
                                                    <line x1={base_svg_x*item + (item === 0 ? this.state.svg_base_cirle : 0) + this.state.svg_circle + 2} y1={this.state.svg_interval*index2} x2={base_svg_x*(item+1)-this.state.svg_circle} y2={this.state.svg_interval*index2}></line>
                                                    <circle cx={base_svg_x*(item+1)} cy={this.state.svg_interval*index2} r={this.state.svg_circle}></circle>
                                                    <text x={base_svg_x*(item+1) - 3} y={this.state.svg_interval*index2 + 4}>{item+2}</text>
                                                </g>
                                            )
                                        }else{
                                            return (
                                                <g key={item2} className={this.getClassName(item+2, item2, servsId)}>
                                                    <line x1={base_svg_x*item + (item === 0 ? this.state.svg_base_cirle : 0) + this.state.svg_circle + 2} y1={this.state.svg_interval*index2} x2={base_svg_x*(item+1)-this.state.svg_circle} y2={this.state.svg_interval*index2}></line>
                                                    <circle cx={base_svg_x*(item+1)} cy={this.state.svg_interval*index2} r={this.state.svg_circle}></circle>
                                                    <text x={base_svg_x*(item+1) - 3} y={this.state.svg_interval*index2 + 4}>{item+2}</text>
                                                    <text x={base_svg_x*(item+1)+20} y={this.state.svg_interval*index2}>{item2}</text>
                                                </g>
                                            )
                                        }
                                    })
                                }
                            })}
                        </g>
                    </svg>
                    <div className="wl-task-log">
                        <div className="wl-task-log__body">
                            <pre>
                            {this.state.svg_logs[servsId].map((item3, key3) => {
                                return (
                                    <div className="wl-task-log__line" key={key3}>
                                        {/*eslint-disable-next-line*/}
                                        <a></a>
                                        <span className={item3.level}>{item3.title}</span>
                                    </div>
                                )
                            })}
                            </pre>
                        </div>
                    </div> 
                </div>
            : null;
            })}
        </div>
        )
    }
}

function mapStateToProps (state) {
    return {
        deployUrl: state.deploy.deployUrl,
        serversList: state.tasks.serversList,
        deployStatus: state.tasks.deployStatus,
        testHost: state.tasks.testHost,
        prevHost: state.tasks.prevHost,
    }
  }
  
  export default connect(mapStateToProps)(App);